package com.yizisu.basemvvm.utils.websocket.socketio

import com.github.nkzawa.emitter.Emitter
import com.github.nkzawa.socketio.client.IO
import com.github.nkzawa.socketio.client.Socket
import com.yizisu.basemvvm.logI
import com.yizisu.basemvvm.utils.tryError
import com.yizisu.basemvvm.utils.websocket.BaseWebSocket
import com.yizisu.basemvvm.utils.websocket.WebSocketState
import org.json.JSONObject
import java.nio.ByteBuffer


class SocketIo(private val webSocketUrl: String) : BaseWebSocket() {
    private var socket: Socket? = null
    override var webSocketState: WebSocketState = WebSocketState.NoConnect

    private val socketListener = mapOf(
            //发生错误
            Socket.EVENT_ERROR to Emitter.Listener {
                printSocketIo(it, "EVENT_ERROR")
            },
            //已连接
            Socket.EVENT_CONNECT to Emitter.Listener {
                printSocketIo(it, "EVENT_CONNECT")
                webSocketState = WebSocketState.Connected
            },
            //连接错误
            Socket.EVENT_CONNECT_ERROR to Emitter.Listener {
                printSocketIo(it, "EVENT_CONNECT_ERROR")
                webSocketState = WebSocketState.NoConnect
            },
            //连接超时
            Socket.EVENT_CONNECT_TIMEOUT to Emitter.Listener {
                printSocketIo(it, "EVENT_CONNECT_TIMEOUT")
                webSocketState = WebSocketState.NoConnect
            },
            //断开连接
            Socket.EVENT_DISCONNECT to Emitter.Listener {
                printSocketIo(it, "EVENT_DISCONNECT")
                webSocketState = WebSocketState.NoConnect
            },
            //正在重连中
            Socket.EVENT_RECONNECTING to Emitter.Listener {
                printSocketIo(it, "EVENT_RECONNECTING")
                webSocketState = WebSocketState.Connecting
            },
            //重连成功
            Socket.EVENT_RECONNECT to Emitter.Listener {
                printSocketIo(it, "EVENT_RECONNECT")
                webSocketState = WebSocketState.Connected
            },
            //重连错误
            Socket.EVENT_RECONNECT_ERROR to Emitter.Listener {
                printSocketIo(it, "EVENT_RECONNECT_ERROR")
                webSocketState = WebSocketState.NoConnect
            },
            //重连失败
            Socket.EVENT_RECONNECT_FAILED to Emitter.Listener {
                printSocketIo(it, "EVENT_RECONNECT_FAILED")
                webSocketState = WebSocketState.NoConnect
            },
            //接收消息
            Socket.EVENT_MESSAGE to Emitter.Listener {
                printSocketIo(it, "EVENT_MESSAGE")
                it.forEach { msg ->
                    onMessageCall?.invoke(msg)
                }
            }
    )


    private fun byteBuffer2ByteArray(byteBuffer: ByteBuffer): ByteArray? {
        val len = byteBuffer.limit() - byteBuffer.position()
        val bytes = ByteArray(len)
        if (byteBuffer.isReadOnly) {
            return null
        } else {
            byteBuffer.get(bytes)
        }
        return bytes
    }

    override fun connect() {
        disConnect()
        val opts = IO.Options()
        opts.forceNew = true
        opts.reconnection = true
        //默认会自动断开重连
        socket = IO.socket(webSocketUrl)
        for ((eventName, listener) in socketListener) {
            socket?.on(eventName, listener)
        }
        socket?.connect()
        webSocketState = WebSocketState.Connecting
    }

    override fun disConnect() {
        tryError {
            socket?.off()
            socket?.disconnect()
            socket?.close()
        }
    }



    override fun sendMessage(msg: Any?): Boolean {
        return if (msg == null) {
            logI("SocketIo-->发送失败:ByteArray is null")
            false
        } else {
            startSend(arrayOf(msg))
        }
    }

    override fun sendMessageWaitConnect(msg: Any?) {

    }

    /**
     * 开始发送消息
     */
    private fun startSend(msg: Array<out Any>?): Boolean {
        printSocketIo(msg, "发送消息")
        return if (socket?.connected() == true) {
            //发送成功
            msg?.forEach {
                when (it) {
                    is String -> {
                        socket?.send(JSONObject(it))
                    }
                    is ByteArray -> {
                        socket?.send(it)
                    }
                    else -> {
                        socket?.send(it)
                    }
                }
            }
            logI("SocketIo-->发送成功")
            true
        } else {
            //发送失败
            logI("SocketIo-->发送失败")
            false
        }
    }

    /**
     * 打印日志
     */
    private fun printSocketIo(it: Array<out Any>?, eventName: String) {
        if (it.isNullOrEmpty()) {
            logI("SocketIo-->${eventName}_no_msg")
            return
        }
        it.forEach { msg ->
            when (msg) {
                is ByteArray -> {
                    logI("SocketIo-->${eventName}_ByteArray，${msg.clone().toList()}")
                }
                is String -> {
                    logI("SocketIo-->${eventName}_String:${msg}")
                }
                is JSONObject -> {
                    logI("SocketIo-->${eventName}_JSONObject:${msg}")
                }
                else -> {
                    logI("SocketIo-->${eventName}_Else:${msg}")
                }
            }
        }
    }

    override fun isConnect(): Boolean {
        return webSocketState == WebSocketState.Connected
    }

    override fun getRealWebSocket(): Any? {
        return socket
    }
}